home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / CTOOLS10.ARJ / LIST.C < prev    next >
C/C++ Source or Header  |  1991-12-31  |  11KB  |  347 lines

  1. /****************************************************************************
  2. *
  3. *                    Copyright (C) 1991 Kendall Bennett.
  4. *                            All rights reserved.
  5. *
  6. * Filename:        $RCSfile: list.c $
  7. * Version:        $Revision: 1.9 $
  8. *
  9. * Language:        ANSI C
  10. * Environment:    any
  11. *
  12. * Description:    Module to implement linked lists. Includes a routine to
  13. *                peform a mergesort on the linked list.
  14. *
  15. * $Id: list.c 1.9 91/12/31 19:40:15 kjb Exp $
  16. *
  17. * Revision History:
  18. * -----------------
  19. *
  20. * $Log:    list.c $
  21. * Revision 1.9  91/12/31  19:40:15  kjb
  22. * Modified include file directories.
  23. * Revision 1.8  91/10/28  03:17:14  kjb
  24. * Ported to the Iris.
  25. * Revision 1.7  91/09/03  18:28:15  ROOT_DOS
  26. * Ported to UNIX.
  27. * Revision 1.6  91/09/01  17:31:07  ROOT_DOS
  28. * Fixed bug in lst_deletenext().
  29. * Revision 1.5  91/09/01  17:17:37  ROOT_DOS
  30. * Changed lst_deletenext() to return a pointer to the deleted node's
  31. * userspace.
  32. * Revision 1.4  91/09/01  16:04:09  ROOT_DOS
  33. * Minor cosmetic change
  34. * Revision 1.3  91/09/01  01:49:59  ROOT_DOS
  35. * Changed search for include files to search the current directory.
  36. * Added function lst_kill() to delete the nodes in the list, calling a user
  37. * supplied function to kill each node.
  38. * Revision 1.2  91/08/21  14:32:02  ROOT_DOS
  39. * Optimized the mergesort routine by eliminating passing the end of the
  40. * merged list found in merge(), back to the main mergesort() routine. This
  41. * eliminated the need to traverse the newly merged list to find the end. 
  42. * Gives about 10% speed improvement for moderate size lists.
  43. * Revision 1.1  91/08/21  14:10:39  ROOT_DOS
  44. * Initial revision
  45. ****************************************************************************/
  46.  
  47. #include <stdio.h>
  48. #include <malloc.h>
  49. #include <signal.h>
  50. #include "debug.h"
  51. #include "list.h"
  52.  
  53. PUBLIC void *lst_newnode(int size)
  54. /****************************************************************************
  55. *
  56. * Function:        lst_newnode
  57. * Parameters:    size    - Amount of memory to allocate for node
  58. * Returns:      Pointer to the allocated node's user space.
  59. *
  60. * Description:    Allocates the memory required for a node, adding a small
  61. *                header at the start of the node. We return a reference to
  62. *                the user space of the node, as if it had been allocated via
  63. *                malloc().
  64. *
  65. ****************************************************************************/
  66. {
  67.     LST_BUCKET    *node;
  68.  
  69.     if ( !(node = (LST_BUCKET*)malloc(size + sizeof(LST_BUCKET))) ) {
  70.         fprintf(stderr,"Not enough memory to allocate list node.\n");
  71.         raise(SIGABRT);
  72.         return NULL;
  73.         }
  74.  
  75.     return LST_USERSPACE(node);            /* Return pointer to user space */
  76. }
  77.  
  78. PUBLIC void lst_freenode(void *node)
  79. /****************************************************************************
  80. *
  81. * Function:        lst_freenode
  82. * Parameters:    node    - Node to free.
  83. *
  84. * Description:  Frees a node previously allocated with lst_newnode().
  85. *
  86. ****************************************************************************/
  87. {
  88.     free(LST_HEADER(node));
  89. }
  90.  
  91. PUBLIC LIST *lst_init(void)
  92. /****************************************************************************
  93. *
  94. * Function:        lst_init
  95. * Returns:      Pointer to a newly created list.
  96. *
  97. * Description:    Initialises a list and returns a pointer to it.
  98. *
  99. ****************************************************************************/
  100. {
  101.     LIST    *l;
  102.  
  103.     if ((l = (LIST*)malloc(sizeof(LIST))) != NULL) {
  104.         l->count = 0;
  105.         l->head = &(l->hz[0]);
  106.         l->z = &(l->hz[1]);
  107.         l->head->next = l->z->next = l->z;
  108.         }
  109.     else {
  110.         fprintf(stderr,"Insufficient memory to allocate list\n");
  111.         raise(SIGABRT);
  112.         return NULL;
  113.         }
  114.  
  115.     return l;
  116. }
  117.  
  118. PUBLIC void lst_kill(LIST *l,void (*freeNode)(void *node))
  119. /****************************************************************************
  120. *
  121. * Function:        lst_kill
  122. * Parameters:    l            - List to kill
  123. *                freeNode    - Pointer to user routine to free a node
  124. *
  125. * Description:    Kills the list l, by deleting all of the elements contained
  126. *                within the list one by one and then deleting the list
  127. *                itself. Note that we call the user supplied routine
  128. *                (*freeNode)() to free each list node. This allows the user
  129. *                program to perform any extra processing needed to kill each
  130. *                node (if each node contains pointers to other items on the
  131. *                heap for example). If no extra processing is required, just
  132. *                pass the address of lst_freenode(), ie:
  133. *
  134. *                    lst_kill(myList,lst_freenode);
  135. *
  136. ****************************************************************************/
  137. {
  138.     LST_BUCKET    *n,*p;
  139.  
  140.     n = l->head->next;
  141.     while (n != l->z) {            /* Free all nodes in list                */
  142.         p = n;
  143.         n = n->next;
  144.         (*freeNode)(LST_USERSPACE(p));
  145.         }
  146.     free(l);                    /* Free the list itself                    */
  147. }
  148.  
  149. PUBLIC void lst_insertafter(LIST *l,void *node,void *after)
  150. /****************************************************************************
  151. *
  152. * Function:        lst_insertafter
  153. * Parameters:    l        - List to insert node into
  154. *                node    - Pointer to user space of node to insert
  155. *                after    - Pointer to user space of node to insert node after
  156. *
  157. * Description:    Inserts a new node into the list after the node 'after'. To
  158. *                insert a new node at the beginning of the list, user the
  159. *                macro LST_HEAD in place of 'after'. ie:
  160. *
  161. *                    lst_insertafter(mylist,node,LST_HEAD(mylist));
  162. *
  163. ****************************************************************************/
  164. {
  165.     LST_BUCKET    *n = LST_HEADER(node),*a = LST_HEADER(after);
  166.  
  167.     n->next = a->next;
  168.     a->next = n;
  169.     l->count++;
  170. }
  171.  
  172. PUBLIC void *lst_deletenext(LIST *l,void *node)
  173. /****************************************************************************
  174. *
  175. * Function:        lst_deletenext
  176. * Parameters:    l        - List to delete node from.
  177. *                node    - Node to delete the next node from
  178. * Returns:        Pointer to the deleted node's userspace.
  179. *
  180. * Description:    Removes the node AFTER 'node' from the list l.
  181. *
  182. ****************************************************************************/
  183. {
  184.     LST_BUCKET    *n = LST_HEADER(node);
  185.  
  186.     node = LST_USERSPACE(n->next);
  187.     n->next = n->next->next;
  188.     l->count--;
  189.     return node;
  190. }
  191.  
  192. PUBLIC void *lst_first(LIST *l)
  193. /****************************************************************************
  194. *
  195. * Function:        lst_first
  196. * Parameters:    l        - List to obtain first node from
  197. * Returns:        Pointer to first node in list, NULL if list is empty.
  198. *
  199. * Description:    Returns a pointer to the user space of the first node in
  200. *                the list. If the list is empty, we return NULL.
  201. *
  202. ****************************************************************************/
  203. {
  204.     LST_BUCKET    *n;
  205.  
  206.     n = l->head->next;
  207.     return (n == l->z ? NULL : LST_USERSPACE(n));
  208. }
  209.  
  210. PUBLIC void *lst_next(void *prev)
  211. /****************************************************************************
  212. *
  213. * Function:        lst_next
  214. * Parameters:    prev    - Previous node in list to obtain next node from
  215. * Returns:        Pointer to the next node in the list, NULL at end of list.
  216. *
  217. * Description:    Returns a pointer to the user space of the next node in the
  218. *                list given a pointer to the user space of the previous node.
  219. *                If we have reached the end of the list, we return NULL. The
  220. *                end of the list is detected when the next pointer of a node
  221. *                points back to itself, as does the dummy last node's next
  222. *                pointer. This enables us to detect the end of the list
  223. *                without needed access to the list data structure itself.
  224. *
  225. *                NOTE:    We do no checking to ensure that 'prev' is NOT a
  226. *                        NULL pointer.
  227. *
  228. ****************************************************************************/
  229. {
  230.     LST_BUCKET    *n = LST_HEADER(prev);
  231.  
  232.     n = n->next;
  233.     return (n == n->next ? NULL : LST_USERSPACE(n));
  234. }
  235.  
  236. /* Static globals required by merge()    */
  237.  
  238. static LST_BUCKET    *z;
  239. static int             (*cmp)(void*,void*);
  240.  
  241. PRIVATE LST_BUCKET *merge(LST_BUCKET *a,LST_BUCKET *b,LST_BUCKET **end)
  242. /****************************************************************************
  243. *
  244. * Function:        merge
  245. * Parameters:    a,b        - Sublist's to merge
  246. * Returns:        Pointer to the merged sublists.
  247. *
  248. * Description:    Merges two sorted lists of nodes together into a single
  249. *                sorted list.
  250. *
  251. ****************************************************************************/
  252. {
  253.     LST_BUCKET    *c;
  254.  
  255.     /* Go through the lists, merging them together in sorted order    */
  256.  
  257.     c = z;
  258.     while (a != z && b != z) {
  259.         if ((*cmp)(LST_USERSPACE(a),LST_USERSPACE(b)) <= 0) {
  260.             c->next = a; c = a; a = a->next;
  261.             }
  262.         else {
  263.             c->next = b; c = b; b = b->next;
  264.             }
  265.         };
  266.  
  267.     /* If one of the lists is not exhausted, then re-attach it to the end
  268.      * of the newly merged list
  269.      */
  270.  
  271.     if (a != z) c->next = a;
  272.     if (b != z) c->next = b;
  273.  
  274.     /* Set *end to point to the end of the newly merged list    */
  275.  
  276.     while (c->next != z) c = c->next;
  277.     *end = c;
  278.  
  279.     /* Determine the start of the merged lists, and reset z to point to
  280.      * itself
  281.      */
  282.  
  283.     c = z->next; z->next = z;
  284.     return c;
  285. }
  286.  
  287. PUBLIC void lst_mergesort(LIST *l,int (*cmp_func)(void*,void*))
  288. /****************************************************************************
  289. *
  290. * Function:        lst_mergesort
  291. * Parameters:    l            - List to merge sort
  292. *                cmp_func    - Function to compare two user spaces
  293. *
  294. * Description:    Mergesort's all the nodes in the list. 'cmp' must point to
  295. *                a comparison function that can compare the user spaces of
  296. *                two different nodes. 'cmp' should work the same as
  297. *                strcmp(), in terms of the values it returns.
  298. *
  299. ****************************************************************************/
  300. {
  301.     int            i,N;
  302.     LST_BUCKET    *a,*b;        /* Pointers to sublists to merge            */
  303.     LST_BUCKET    *c;            /* Pointer to end of sorted sublists        */
  304.     LST_BUCKET    *head;        /* Pointer to dummy head node for list        */
  305.     LST_BUCKET    *todo;        /* Pointer to sublists yet to be sorted        */
  306.     LST_BUCKET    *t;            /* Temporary                                */
  307.  
  308.     /* Set up globals required by merge() and pointer to head    */
  309.  
  310.     z = l->z; cmp = cmp_func; head = l->head;
  311.  
  312.     for (N = 1,a = z; a != head->next; N = N + N) {
  313.         todo = head->next; c = head;
  314.         while (todo != z) {
  315.  
  316.             /* Build first sublist to be merged, and splice from main list
  317.              */
  318.  
  319.             a = t = todo;
  320.             for (i = 1; i < N; i++) t = t->next;
  321.             b = t->next; t->next = z; t = b;
  322.  
  323.             /* Build second sublist to be merged and splice from main list
  324.              */
  325.  
  326.             for (i = 1; i < N; i++) t = t->next;
  327.             todo = t->next; t->next = z;
  328.  
  329.             /* Merge the two sublists created, and set 'c' to point to the
  330.              * end of the newly merged sublists.
  331.              */
  332.  
  333.             c->next = merge(a,b,&t); c = t;
  334.             }
  335.         }
  336. }
  337.